<?php
/**
 * Created by PhpStorm.
 * User: 666
 * Date: 2020/5/5
 * Time: 9:41
 */


namespace App\IpLimit;

use App\Consts\RedisKey;
use EasySwoole\Component\Singleton;
use EasySwoole\Component\TableManager;
use EasySwoole\EasySwoole\Config;
use EasySwoole\EasySwoole\ServerManager;
use EasySwoole\RedisPool\Redis;
use Swoole\Table;
use App\Utility\Response;
class IpList
{
    use Singleton;

    /** @var Table */
    protected $table;

    public  function __construct()
    {
        TableManager::getInstance()->add('ipList', [
            'ip' => [
                'type' => Table::TYPE_STRING,
                'size' => 16
            ],
            'count' => [
                'type' => Table::TYPE_INT,
                'size' => 8
            ],
            'lastAccessTime' => [
                'type' => Table::TYPE_INT,
                'size' => 10
            ]
        ], 1024*128);
        $this->table = TableManager::getInstance()->get('ipList');
    }

    function access(string $ip,$uri):int
    {
        $key  = substr(md5($ip.$uri), 8,16);
        $info = $this->table->get($key);

        if ($info) {
            $this->table->set($key, [
                'lastAccessTime' => time(),
                'count'          => $info['count'] + 1,
            ]);
            return $info['count'] + 1;
        }else{
            $this->table->set($key, [
                'ip'             => $ip,
                'lastAccessTime' => time(),
                'count'          => $info['count'] + 1,
            ]);
            return 1;
        }
    }

    function getKey($ip){

        return  $key  = substr(md5($ip), 8,16);
    }


    function clear()
    {
        foreach ($this->table as $key => $item){

            $this->table->del($key);
        }
    }



    function violationIp($ip){

        $data = Redis::defer('redis')->incr(RedisKey::VIOLATION_IP_RECORD.$ip);
        $count = Config::getInstance()->getConf('ipAccessCount.count');
        if($data >= $count){

            Redis::defer('redis')->zAdd(RedisKey::IP_PRISON, time(), $ip);
            Redis::defer('redis')->del(RedisKey::VIOLATION_IP_RECORD.$ip);

        }

    }

    function accessList($count = 10):array
    {
        $ret = [];
        foreach ($this->table as $key => $item){

            if ($item['count'] >= $count){
                $ret[] = ['key'=> $key ,'val'=> $item ];
            }
        }
        return $ret;
    }


    function verification($request){

        $fd = $request->getSwooleRequest()->fd;
        $ip = ServerManager::getInstance()->getSwooleServer()->getClientInfo($fd)['remote_ip'];

        $uri = $request->getUri()->getPath();
        $count = Config::getInstance()->getConf('ipAccessCount.count');
        $key = IpList::getInstance()->getKey($ip.$uri);
        $logcount = IpList::getInstance()->access($ip,$uri);
//        var_dump('logcount:',$logcount);
        if ($logcount >= $count) {

            $count = Redis::defer('redis')->get(RedisKey::VIOLATION_IP_RECORD.$key);
            Response::responseJson(1500 , "您已违规$count 次,请不要在5秒内多次重复请求,违规10次及以上将被屏蔽1小时");
            //强制关闭
//            ServerManager::getInstance()->getSwooleServer()->close($fd);
            return false;
        }
        $res = Redis::defer('redis')->zScore(RedisKey::IP_PRISON,$key);
        if($res){
            Response::responseJson(1501 , "您已被屏蔽,将在".date('Y-m-d H:i:s',$res+3600).'解封');
            return false;
        }

        return  true;
    }

}